<?php

header('Content-type: application/json;charset=utf-8');
error_reporting(E_ERROR | E_PARSE);
date_default_timezone_set('PRC');

define('ROOT_DIR', dirname(__FILE__));
define('LOG_DIR', ROOT_DIR . '/logs/');
define('DEBUG_MODE', false);
define('CACHE_KEY_PREFIX', '');

require(ROOT_DIR . '/includes/autoload.php');
require(ROOT_DIR . '/includes/config.php');
require(ROOT_DIR . '/includes/function.php');

class calcDate
{
    private $db;
    private $tg = ["甲", "乙", "丙", "丁", "戊", "己", "庚", "辛", "壬", "癸"];
    private $dz = ["子", "丑", "寅", "卯", "辰", "巳", "午", "未", "申", "酉", "戌", "亥"];
    private $jq = ["立春", "惊蛰", "清明", "立夏", "芒种", "小暑", "立秋", "白露", "寒露", "立冬", "大雪", "小寒"];

    public function __construct()
    {
        $conf     = getConfig();
        $dbset    = [
            'dsn'      => 'mysql:host=' . $conf->mysql->host . ';dbname=' . $conf->mysql->database,
            'name'     => $conf->mysql->user,
            'password' => $conf->mysql->password,
        ];
        $this->db = new \DB($dbset);
    }

    public function run($date): void
    {
        $Y = $ytg = $ydz = $yny = $M = $mtg = $mdz = $mny = $dtg = $ddz = $dny = $htg = $hdz = $hny = 0;
        $temp      = [5, 7, 6, 7, 7, 8, 9, 9, 9, 8, 8, 7];
        $timestamp = 0;
        $dataset   = [];
        do {
            if (preg_match('#(\d+)-(\d+)-(\d+)\s+(\d+):(\d+)#', $date, $dateRow)) {
                $tempy = $dateRow[1];
                $tempm = $dateRow[2];
                $D     = $dateRow[3];
                $H     = $dateRow[4];
                if ($tempy > 2100 || $tempy < 1800) {
                    $dataset = [
                        'ret' => 10001,
                        'msg' => '请输入1900-2100年之间的日期',
                    ];
                    break;
                }
                if ($tempm > 12 || $tempm < 1) {
                    $dataset = [
                        'ret' => 10002,
                        'msg' => '月份输入有误',
                    ];
                    break;
                }
                if ($D > 31 || $D < 1) {
                    $dataset = [
                        'ret' => 10003,
                        'msg' => '日期输入有误',
                    ];
                    break;
                }
                if ($H > 59 || $H < 0) {
                    $dataset = [
                        'ret' => 10004,
                        'msg' => '时间输入有误',
                    ];
                    break;
                }
                $timestamp = strtotime($tempy . '-' . $tempm . '-' . $D . ' ' . $H . ':' . $dateRow[5] . ':59');
            } else {
                $dataset = [
                    'ret' => 10000,
                    'msg' => '日期格式有误, 格式如:(2020-09-15 21:32)',
                ];
                break;
            }
            if ($tempm == 2 && $D >= 3 && $D < 5) {
                $tempd = $this->db->getOne("SELECT `time` FROM `solar_terms` where year='{$tempy}' and name='{$this->jq[0]}' limit 1");
                if ($timestamp >= strtotime($tempd)) {
                    $temp[0] = date('j', strtotime($tempd));
                }
            }
            if ($tempm > 2 || $tempm == 2 && $D >= $temp[0]) {
                $Y = $tempy;
            } else {
                $Y = $tempy - 1;  /*对年份的修正*/
            }
            switch ($tempm) {
                case 2:
                {
                    if ($D >= $temp[0]) {
                        $M = 1;
                    } else {
                        $M = 12;
                    }
                    break;
                }
                case 3:
                {
                    if ($D >= 5 && $D < 7) {
                        $tempd = $this->db->getOne("SELECT `time` FROM `solar_terms` where year='{$tempy}' and name='{$this->jq[1]}' limit 1");
                        if ($timestamp >= strtotime($tempd)) {
                            $temp[1] = date('j', strtotime($tempd));
                        }
                    }
                    if ($D >= $temp[1]) {
                        $M = 2;
                    } else {
                        $M = 1;
                    }
                    break;
                }
                case 4:
                {
                    if ($D >= 4 && $D < 6) {
                        $tempd = $this->db->getOne("SELECT `time` FROM `solar_terms` where year='{$tempy}' and name='{$this->jq[2]}' limit 1");
                        if ($timestamp >= strtotime($tempd)) {
                            $temp[2] = date('j', strtotime($tempd));
                        }
                    }
                    if ($D >= $temp[2])
                        $M = 3;
                    else
                        $M = 2;
                    break;
                }
                case 5:
                {
                    if ($D >= 5 && $D < 7) {
                        $tempd = $this->db->getOne("SELECT `time` FROM `solar_terms` where year='{$tempy}' and name='{$this->jq[3]}' limit 1");
                        if ($timestamp >= strtotime($tempd)) {
                            $temp[3] = date('j', strtotime($tempd));
                        }
                    }
                    if ($D >= $temp[3]) {
                        $M = 4;
                    } else {
                        $M = 3;
                    }
                    break;
                }
                case 6:
                {
                    if ($D >= 5 && $D < 7) {
                        $tempd = $this->db->getOne("SELECT `time` FROM `solar_terms` where year='{$tempy}' and name='{$this->jq[4]}' limit 1");
                        if ($timestamp >= strtotime($tempd)) {
                            $temp[4] = date('j', strtotime($tempd));
                        }
                    }
                    if ($D >= $temp[4]) {
                        $M = 5;
                    } else {
                        $M = 4;
                    }
                    break;
                }
                case 7:
                {
                    if ($D >= 6 && $D < 8) {
                        $tempd = $this->db->getOne("SELECT `time` FROM `solar_terms` where year='{$tempy}' and name='{$this->jq[5]}' limit 1");
                        if ($timestamp >= strtotime($tempd)) {
                            $temp[5] = date('j', strtotime($tempd));
                        }
                    }
                    if ($D >= $temp[5]) {
                        $M = 6;
                    } else {
                        $M = 5;
                    }
                    break;
                }
                case 8:
                {
                    if ($D >= 7 && $D < 9) {
                        $tempd = $this->db->getOne("SELECT `time` FROM `solar_terms` where year='{$tempy}' and name='{$this->jq[6]}' limit 1");
                        if ($timestamp >= strtotime($tempd)) {
                            $temp[6] = date('j', strtotime($tempd));
                        }
                    }
                    if ($D >= $temp[6]) {
                        $M = 7;
                    } else {
                        $M = 6;
                    }
                    break;
                }
                case 9:
                {
                    if ($D >= 7 && $D < 9) {
                        $tempd = $this->db->getOne("SELECT `time` FROM `solar_terms` where year='{$tempy}' and name='{$this->jq[7]}' limit 1");
                        if ($timestamp >= strtotime($tempd)) {
                            $temp[7] = date('j', strtotime($tempd));
                        }
                    }
                    if ($D >= $temp[7]) {
                        $M = 8;
                    } else {
                        $M = 7;
                    }
                    break;
                }
                case 10:
                {
                    if ($D >= 8 && $D < 9) {
                        $tempd = $this->db->getOne("SELECT `time` FROM `solar_terms` where year='{$tempy}' and name='{$this->jq[8]}' limit 1");
                        if ($timestamp >= strtotime($tempd)) {
                            $temp[8] = date('j', strtotime($tempd));
                        }
                    }
                    if ($D >= $temp[8]) {
                        $M = 9;
                    } else {
                        $M = 8;
                    }
                    break;
                }
                case 11:
                {
                    if ($D >= 7 && $D < 8) {
                        $tempd = $this->db->getOne("SELECT `time` FROM `solar_terms` where year='{$tempy}' and name='{$this->jq[9]}' limit 1");
                        if ($timestamp >= strtotime($tempd)) {
                            $temp[9] = date('j', strtotime($tempd));
                        }
                    }
                    if ($D >= $temp[9]) {
                        $M = 10;
                    } else {
                        $M = 9;
                    }
                    break;
                }
                case 12:
                {
                    if ($D >= 6 && $D < 8) {
                        $tempd = $this->db->getOne("SELECT `time` FROM `solar_terms` where year='{$tempy}' and name='{$this->jq[10]}' limit 1");
                        if ($timestamp >= strtotime($tempd)) {
                            $temp[10] = date('j', strtotime($tempd));
                        }
                    }
                    if ($D >= $temp[10]) {
                        $M = 11;
                    } else {
                        $M = 10;
                    }
                    break;
                }
                case 1:
                {
                    if ($D >= 5 && $D < 7) {
                        $tempd = $this->db->getOne("SELECT `time` FROM `solar_terms` where year='{$tempy}' and name='{$this->jq[11]}' limit 1");
                        if ($timestamp >= strtotime($tempd)) {
                            $temp[11] = date('j', strtotime($tempd));
                        }
                    }
                    if ($D >= $temp[11]) {
                        $M = 12;
                    } else {
                        $M = 11;
                    }
                    break;
                }
                default:
                {
                    throw new Exception("\n月份输入有误，请重新输入!\n");
                }
            }
            $this->ycompute($Y, $ytg, $ydz);
            $this->mcompute($Y, $M, $mtg, $mdz);
            $this->dcompute($tempy, $tempm, $D, $H, $dtg, $ddz);
            $this->hcompute($H, $dtg, $htg, $hdz);
            /*数据处理程序段*/
            $dataset = [
                'ret'  => 0,
                'data' => [
                    'calc'  => $date,
                    'year'  => $this->tg[$ytg - 1] . $this->dz[$ydz - 1],
                    'month' => $this->tg[$mtg - 1] . $this->dz[$mdz - 1],
                    'day'   => $this->tg[$dtg - 1] . $this->dz[$ddz - 1],
                    'hour'  => $this->tg[$htg - 1] . $this->dz[$hdz - 1],
                    'curr'  => $this->db->getRow("SELECT `name`,`time` FROM `solar_terms` where `time`<='{$date}' order by time desc limit 1"),
                    'next'  => $this->db->getRow("SELECT `name`,`time` FROM `solar_terms` where `time`>='{$date}' order by time asc  limit 1"),
                ],
            ];
        } while (FALSE);
        echo json_encode($dataset, JSON_UNESCAPED_UNICODE);
    }

    /*判断某年是否为闰年，闰年返回1，否则返回0。*/
    private function Isleapyear(int $year): int
    {
        return ($year % 400 == 0) || ($year % 100 != 0) && ($year % 4 == 0) ? 1 : 0;
    }

    /*年柱处理子程序*/
    private function ycompute(int $year, int &$tg, int &$dz): void
    {
        if ($year <= 3) {
            $year += 60;
        }
        $year -= 3;
        $tg   = $year % 10;
        if ($tg == 0) {
            $tg = 10;
        }
        $dz = $year % 12;
        if ($dz == 0) {
            $dz = 12;
        }
    }

    /*月柱处理子程序*/
    private function mcompute(int $year, int $month, int &$tg, int &$dz): void
    {
        $dz = $month + 2;
        if ($dz > 12) {
            $dz -= 12;
        }
        $tg = ($year % 5 - 2) * 2 - 2;
        if ($tg < 0) {
            $tg += 10;
        }
        $tg = $tg + $month;
        if ($tg > 10) {
            $tg -= 10;
        }
    }

    /*日柱处理子程序*/
    private function dcompute(int $year, int $month, $day, int $hour, int &$tg, int &$dz): void
    {
        $odds      = ($month % 2) ? 0 : 30;
        $bigMonths = 0;
        switch ($month) {
            case 1:
                $bigMonths = 0;
                break;
            case 2:
            case 3:
                $bigMonths = 1;
                break;
            case 4:
            case 5:
                $bigMonths = 2;
                break;
            case 6:
            case 7:
                $bigMonths = 3;
                break;
            case 8:
                $bigMonths = 4;
                break;
            case 9:
            case 10:
                $bigMonths = 5;
                break;
            case 11:
            case 12:
                $bigMonths = 6;
                break;
        }
        if ($month > 2) {
            $base = (10 + ($year - 1900) * 5 + intval(($year - 1900) / 4) + $bigMonths + $odds + $day - 2) % 60;
        } else {
            if( $this->Isleapyear($year) ){
                $base = (10 + ($year - 1900) * 5 + intval(($year - 1900) / 4) + $bigMonths + $odds + $day -1) % 60;
            }else{
                $base = (10 + ($year - 1900) * 5 + intval(($year - 1900) / 4) + $bigMonths + $odds + $day) % 60;
            }
        }
        $tg = $base % 10;
        if ($tg == 0) {
            $tg = 10;
        }
        $dz = $base % 12;
        if ($dz == 0) {
            $dz = 12;
        }
        if ($hour >= 23) {
            ++$tg;
            ++$dz;
        }
        if ($tg > 10) {
            $tg -= 10;
        }
        if ($dz > 12) {
            $dz -= 12;
        }
    }

    /*时柱处理子程序*/
    private function hcompute(int $hour, int $dtg, int &$tg, int &$dz): void
    {
        $dh   = 12 - $dtg;
        $hour += 1;
        $hour = intval($hour / 2);
        $dz   = $hour + 1;
        if ($dz > 12) {
            $dz -= 12;
        }
        $tg = $dtg + $dz - $dh;
        if ($tg > 10) {
            $tg -= 10;
        }
        if ($tg < 0) {
            $tg += 10;
        }
        if ($tg == 0) {
            $tg = 10;
        }
    }
}

try {
    $date = $_REQUEST['date'] ?? date('Y-m-d H:i:s');
    (new calcDate())->run($date);
} catch (\Throwable $e) {
    echo $e->getMessage();
}
